﻿
using System;

namespace Test30.Engine
{
    public class Condition
    {
        internal event EventHandler<EventArgs> Changed;

        public bool IsActive => _turnsRemaining != 0;
        public int TurnsRemaining => _turnsRemaining;
        public Condition(Entity entity,Func<Entity,Action> updateCallback,
            Func<Entity,Action> completeCallback)
        {
            _entity = entity;
            _update = updateCallback;
            _complete = completeCallback;
        }

        public Condition(Entity entity, Func<Entity, Action> completeCallback)
            : this(entity, null, completeCallback)
        {
        }

        public void AddDuration(int duration)
        {
            SetDuration(_turnsRemaining + duration);
        }

        public Action Deactivate()
        {
            Action action = null;

            bool wasActive = IsActive;

            _turnsRemaining = 0;

            // shut it down if active
            if (wasActive)
            {
                if (_complete != null)
                {
                    action = _complete(_entity);
                }
                OnChanged();
            }

            return action;
        }
        public void SetDuration(int duration)
        {
            if (duration <= 0) throw new ArgumentOutOfRangeException($"Must set the duration to a positive amount.");
            if (_turnsRemaining < 0) throw new InvalidOperationException($"Cannot increment the duration on a Condition that is set to run indefinitely.");

            bool wasActive = IsActive;

            // add to the duration
            _turnsRemaining = duration;

            // if turning it on for the first time, note the change
            if (!wasActive)
            {
                OnChanged();
            }
        }

        public Action Update()
        {
            Action action = null;
            if (IsActive)
            {

                // positive count means it's timed
                if (_turnsRemaining >= 0)
                {
                    _turnsRemaining--;
                }

                // if the condition has run its course, complete it
                if (!IsActive)
                {
                    if (_complete != null)
                    {
                        action = _complete(_entity);
                    }
                    OnChanged();
                }
                else
                {
                    // otherwise update it
                    if (_update != null)
                    {
                        action = _update(_entity);
                    }
                }
            }

            return action;
        }

        private void OnChanged()
        {
            Changed?.Invoke(this, EventArgs.Empty);
        }

        private int _turnsRemaining;
        private readonly Entity _entity;
        private readonly Func<Entity, Action> _update;
        private readonly Func<Entity, Action> _complete;
    }
}
